package zack.gateway.center.interfaces;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.web.bind.annotation.*;
import zack.gateway.center.application.IConfigManageService;
import zack.gateway.center.application.ILoadBalancingService;
import zack.gateway.center.application.IMessageService;
import zack.gateway.center.domain.docker.model.aggregates.NginxConfig;
import zack.gateway.center.domain.docker.model.vo.LocationVO;
import zack.gateway.center.domain.docker.model.vo.UpstreamVO;
import zack.gateway.center.domain.manage.model.aggregates.ApplicationSystemRichInfo;
import zack.gateway.center.domain.manage.model.vo.GatewayServerDetailVO;
import zack.gateway.center.domain.manage.model.vo.GatewayServerVO;
import zack.gateway.center.domain.message.service.config.PublisherConfig;
import zack.gateway.center.infrastructure.common.ResponseCode;
import zack.gateway.center.infrastructure.common.Result;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author   zack
 * @description 网关配置管理；服务分组、网关注册、服务关联
 * 1. 查询网关服务配置项信息：/wg/admin/config/queryServerConfig
 * 2. 注册网关服务节点：/wg/admin/config/registerGateway
   */
@RestController
@RequestMapping("/wg/admin/config")
public class GatewayConfigManage {

    private Logger logger = LoggerFactory.getLogger(GatewayConfigManage.class);
    @Resource
    private IMessageService messageService;
    @Resource
    ILoadBalancingService loadBalancingService;

    @Resource
    private IConfigManageService configManageService;

    @GetMapping(value = "queryServerConfig", produces = "application/json;charset=utf-8")
    public Result<List<GatewayServerVO>> queryServerConfig() {
        try {
            logger.info("查询网关服务配置项信息");
            List<GatewayServerVO> gatewayServerVOList = configManageService.queryGatewayServerList();
            return new Result<>(ResponseCode.SUCCESS.getCode(), ResponseCode.SUCCESS.getInfo(), gatewayServerVOList);
        } catch (Exception e) {
            logger.error("查询网关服务配置项信息异常", e);
            return new Result<>(ResponseCode.UN_ERROR.getCode(), e.getMessage(), null);
        }
    }

    /**
     * 注册网关服务节点
     *
     * @param groupId        分组标识
     * @param gatewayId      网关标识
     * @param gatewayName    网关名称
     * @param gatewayAddress 网关地址
     * @return 注册状态
     */
    @PostMapping(value = "registerGateway")
    public Result<Boolean> registerGatewayServerNode(@RequestParam String groupId,
                                                     @RequestParam String gatewayId,
                                                     @RequestParam String gatewayName,
                                                     @RequestParam String gatewayAddress) {
        try {
            logger.info("注册网关服务节点 gatewayId：{} gatewayName：{} gatewayAddress：{}", gatewayId, gatewayName, gatewayAddress);
            boolean done = configManageService.registerGatewayServerNode(groupId, gatewayId, gatewayName, gatewayAddress);
            if(done) {
                logger.info("注册算力成功");
            }else{
                logger.info("算力注册失败");
            }

            //查询最新网关算力配置
            List<GatewayServerDetailVO> gatewayServerDetailVOList = configManageService.queryGatewayServerDetailList();
            //将同一个组的网关放在一起
            Map<String, List<GatewayServerDetailVO>> details = gatewayServerDetailVOList.stream().collect(Collectors.groupingBy(GatewayServerDetailVO::getGroupId));
            Set<String> groupIds = details.keySet();
            //locationVO是分组,路由和转发的配置
            List<LocationVO> locationVOS = new ArrayList<>();
            for(String name :groupIds){
                LocationVO locationVO = new LocationVO("/" + name + "/", "http://" + name + ";");
                locationVOS.add(locationVO);
            }
            List<UpstreamVO> upstreamVOS = new ArrayList<>();
            for(String name :groupIds){
                List<String> gatewayAddressList = details.get(name).stream().map(GatewayServerDetailVO::getGatewayAddress).collect(Collectors.toList());
                UpstreamVO leastConn = new UpstreamVO(name, "least_conn;", gatewayAddressList);
                upstreamVOS.add(leastConn);
            }
            loadBalancingService.updateNginxConfig(new NginxConfig(upstreamVOS, locationVOS));

            return new Result<>(ResponseCode.SUCCESS.getCode(), ResponseCode.SUCCESS.getInfo(), done);
        } catch (Exception e) {
            logger.error("注册网关服务节点异常", e);
            return new Result<>(ResponseCode.UN_ERROR.getCode(), e.getMessage(), false);
        }
    }

    @PostMapping(value = "queryApplicationSystemRichInfo", produces = "application/json;charset=utf-8")
    public Result<ApplicationSystemRichInfo> queryApplicationSystemRichInfo(@RequestParam String gatewayId,@RequestParam String systemId) {
        try {
            logger.info("查询分配到网关下的待注册系统信息(系统、接口、方法) gatewayId：{}", gatewayId);
            ApplicationSystemRichInfo applicationSystemRichInfo = configManageService.queryApplicationSystemRichInfo(gatewayId,systemId);
            if(applicationSystemRichInfo == null) {
                return new Result<>(ResponseCode.SUCCESS.getCode(), ResponseCode.SUCCESS.getInfo(), null);
            }
            return new Result<ApplicationSystemRichInfo>(ResponseCode.SUCCESS.getCode(), ResponseCode.SUCCESS.getInfo(), applicationSystemRichInfo);
        } catch (Exception e) {
            logger.error("查询分配到网关下的待注册系统信息(系统、接口、方法)异常 gatewayId：{}", gatewayId, e);
            return new Result<>(ResponseCode.UN_ERROR.getCode(), e.getMessage(), null);
        }
    }

    @PostMapping(value = "queryRedisConfig", produces = "application/json;charset=utf-8")
    public Result<Map<String, String>> queryRedisConfig() {
        try {
            logger.info("查询配置中心Redis配置信息");
            Map<String, String> redisConfig = messageService.queryRedisConfig();
            return new Result<>(ResponseCode.SUCCESS.getCode(), ResponseCode.SUCCESS.getInfo(), redisConfig);
        } catch (Exception e) {
            logger.error("查询配置中心Redis配置信息失败", e);
            return new Result<>(ResponseCode.UN_ERROR.getCode(), e.getMessage(), null);
        }
    }

    public Result<Boolean> distributionGatewayServerNode(@RequestParam String groupId,@RequestParam String gatewayId,@RequestParam String systemId) {
        try {
            configManageService.distributionGatewayServerNode(groupId, gatewayId, systemId);
            return new Result<>(ResponseCode.SUCCESS.getCode(), ResponseCode.SUCCESS.getInfo(), true);
        } catch (DuplicateKeyException e) {
            logger.warn("查询应用服务配置项信息失败，唯一索引冲突。groupId：{} gatewayId：{} systemId：{}", groupId, gatewayId, systemId, e);
            return new Result<>(ResponseCode.INDEX_DUP.getCode(), e.getMessage(), true);
        } catch (Exception e) {
            logger.error("网关算力与系统挂载配置。groupId：{} gatewayId：{} systemId：{}", groupId, gatewayId, systemId, e);
            return new Result<>(ResponseCode.UN_ERROR.getCode(), e.getMessage(), false);
        }
    }
}
